module;
#include <type_traits>
#include <cstddef>
export module Code_23_1_2;


// primary template: in general we yield the given type:
template<typename T>
struct RemoveAllExtentsT 
{
    using Type = T;
};

// partial specializations for array types (with and without bounds):
template<typename T, std::size_t SZ>
struct RemoveAllExtentsT<T[SZ]> 
{
    using Type = typename RemoveAllExtentsT<T>::Type;
};

template<typename T>
struct RemoveAllExtentsT<T[]> 
{
    using Type = typename RemoveAllExtentsT<T>::Type;
};

template<typename T>
using RemoveAllExtents = typename RemoveAllExtentsT<T>::Type;

export
namespace Code_23_1_2 {

    void run()
    {
        RemoveAllExtents<int[]>      a; // yields int
        RemoveAllExtents<int[5][10]> b; // yields int
        RemoveAllExtents<int[][10]>  c; // yields int
        RemoveAllExtents<int(*)[5]>  d; // yields int(*)[5]
    }
}